package io.github.bigbird0101.easycluster.registry;

import io.github.bigbird0101.easycluster.URL;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.KeeperException;

import java.nio.charset.StandardCharsets;

public class ZookeeperRegistry extends AbstractRegistry {
    protected static final String PATH_SEPARATOR = "/";
    public static final String EASY_CLUSTER_NODES = PATH_SEPARATOR+ "nodes";
    protected int DEFAULT_CONNECTION_TIMEOUT_MS = 30 * 1000;
    protected int DEFAULT_SESSION_TIMEOUT_MS = 60 * 1000;
    private final CuratorFramework client;

    public ZookeeperRegistry(URL url) {
        super(url);
        this.client = CuratorFrameworkFactory.builder()
                .connectString(url.getHost()+":"+url.getPort())
                .retryPolicy(new RetryNTimes(1, 1000))
                .connectionTimeoutMs(DEFAULT_CONNECTION_TIMEOUT_MS)
                .sessionTimeoutMs(DEFAULT_SESSION_TIMEOUT_MS)
                .build();
        client.start();
    }

    @Override
    public void register(URL url) {
        String path=doGetPath(url);
        long ts = System.currentTimeMillis();
        doCreate(path,String.valueOf(ts));
    }

    private String doGetPath(URL url) {
        String name=getName(url);
        return PATH_SEPARATOR+getRoot()+EASY_CLUSTER_NODES+"/"+name;
    }

    protected void doCreate(String path){
        int i = path.lastIndexOf('/');
        if (i > 0) {
            doCreate(path.substring(0, i));
        }
        addIfAbsent(path);
    }

    protected void doCreate(String path,String data){
        int i = path.lastIndexOf('/');
        if (i > 0) {
            doCreate(path.substring(0, i));
        }
        addIfAbsent(path,data);
    }

    public void addIfAbsent(String path){
        if(notExists(path)){
            try {
                client.create().forPath(path);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void addIfAbsent(String path,String data){
        if(notExists(path)){
            try {
                client.create().forPath(path);
            } catch (Exception e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
        }
        try {
            client.setData().forPath(path,data.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    protected void deletePath(String path) {
        try {
            client.delete().deletingChildrenIfNeeded().forPath(path);
        } catch (KeeperException.NoNodeException ignored) {
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    public boolean notExists(String path) {
        try {
            if (client.checkExists().forPath(path) != null) {
                return false;
            }
        } catch (Exception ignored) {
        }
        return true;
    }

    private String getName(URL url) {
        String host = url.getHost();
        Integer port = url.getPort();
        return host+":"+port;
    }

    @Override
    public void unregister(URL url) {
        deletePath(doGetPath(url));
    }
}
